package com.zhdl.modules.prefiresys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.project.common.service.impl.BaseServiceImpl;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.zhdl.common.ytools.EnumHelper;
import com.zhdl.modules.prefiresys.entity.DetectorHistoryData;
import com.zhdl.modules.prefiresys.entity.QDetector;
import com.zhdl.modules.prefiresys.entity.QDetectorAreaInfo;
import com.zhdl.modules.prefiresys.entity.QDetectorHistoryData;
import com.zhdl.modules.prefiresys.repository.DetectorHistoryDataRepository;
import com.zhdl.modules.prefiresys.service.DetectorHistoryDataService;
import com.zhdl.modules.prefiresys.web.request.DayHistoryListRequest;
import com.zhdl.modules.prefiresys.web.request.HistoryListRequest;
import com.zhdl.modules.prefiresys.web.response.HistoryListQueryResult;
import com.zhdl.modules.prefiresys.web.response.HistoryListResp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 探测器开关量明细数据，用于画曲线
 */
@Slf4j
@Service
public class DetectorHistoryDataServiceImpl extends BaseServiceImpl<String, DetectorHistoryData, DetectorHistoryDataRepository> implements DetectorHistoryDataService {

    @Autowired
    public JPAQueryFactory jpaQueryFactory;


    /**
     * 通过防区id 查询实时浓度
     *
     * @param areaId 防区Id
     * @return 时间-浓度
     */
    @Override
    public List<DetectorHistoryData> findByAreaId(String areaId) {
        // (0) 定义时间格式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //（1）获取当前时间
        LocalDateTime dateNow = LocalDateTime.now();
        //（2）获取当前时间的前几小时时间
        LocalDateTime localDateTime = dateNow.minusHours(2);

        QDetectorHistoryData qd = QDetectorHistoryData.detectorHistoryData;

        List<DetectorHistoryData> lists = jpaQueryFactory.selectFrom(qd)
                .where(
                        qd.areaId.eq(areaId),
                        qd.createDate.gt(dateTimeFormatter.format(localDateTime))
                )
                .orderBy(qd.createDate.asc())
                .fetch();
        return lists;

//        return jpaQueryFactory.selectFrom(qd)
//                .where(
//                        qd.areaId.eq(areaId),
//                        qd.createDate.gt(dateTimeFormatter.format(localDateTime))
//                )
//                .orderBy(qd.createDate.asc())
//                .fetch();

    }


    @Override
    public List<DetectorHistoryData> findNullAndData(String areaId){
        // 定义时间格式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();

        // 生成两小时内的每秒时间戳列表
        List<LocalDateTime> timeList = IntStream.range(0, 2 * 60 * 60)
                .mapToObj(seconds -> now.minusHours(2).plusSeconds(seconds))
                .collect(Collectors.toList());

        // 假设jpaQueryFactory和QDetectorHistoryData已经定义好，并且areaId已经给出
        QDetectorHistoryData qd = QDetectorHistoryData.detectorHistoryData;
        List<DetectorHistoryData> queryResult = jpaQueryFactory.selectFrom(qd)
                .where(qd.areaId.eq(areaId),
                        qd.createDate.gt(dateTimeFormatter.format(now.minusHours(2))))
                .orderBy(qd.createDate.asc())
                .fetch();

        // 根据查询结果填充列表
        List<DetectorHistoryData> filledList = new ArrayList<>(timeList.size());

        var ref = new Object() {
            DetectorHistoryData previousData = new DetectorHistoryData();
        };

        for (LocalDateTime time : timeList) {
            DetectorHistoryData data = new DetectorHistoryData();
            data.setCreateDate(dateTimeFormatter.format(time));

            // 查找查询结果中是否有匹配的时间戳
            Optional<DetectorHistoryData> optionalData = queryResult.stream()
                    .filter(result -> result.getCreateDate().equals(dateTimeFormatter.format(time)))
                    .findFirst();

            // 如果有匹配的数据，则设置数据字段，并更新previousData
            optionalData.ifPresent(result -> {
                        data.setParticlePercent(result.getParticlePercent());
                        data.setSmokePercent(result.getSmokePercent());
                        // 如果当前值不为0，则更新previousData
                        if (result.getParticlePercent() != 0 || result.getSmokePercent() != 0) {
                            ref.previousData = result;
                        }
            });
            // 如果没有匹配的数据，或者匹配的数据中SomkePercent和ParticlePercent都为0，则使用previousData中的值
            if (data.getParticlePercent() == 0 && data.getSmokePercent() == 0) {
                data.setParticlePercent(ref.previousData.getParticlePercent());
                data.setSmokePercent(ref.previousData.getSmokePercent());
            }
            filledList.add(data);
        }

        // 打印填充后的列表，或进行其他处理...
        filledList.forEach(data -> {
            System.out.println(data.getCreateDate());
        });

        return filledList;

    }

    @Override
    public List<HistoryListResp> findDayAllRecord(DayHistoryListRequest request) {
        QDetectorHistoryData qDetectorHistoryData = QDetectorHistoryData.detectorHistoryData;
        QDetectorAreaInfo qDetectorAreaInfo = QDetectorAreaInfo.detectorAreaInfo;
        QDetector qDetector = QDetector.detector;

        BooleanBuilder builder = new BooleanBuilder();
        builder.and(qDetectorHistoryData.startTime.like("%" + request.getDayTime() + "%"));

        if (request.getAreaId().size() > 0) {
            BooleanBuilder builder1 = new BooleanBuilder();
            for (String id : request.getAreaId())
                builder1.or(qDetectorHistoryData.areaId.eq(id));

            builder.and(builder1);
        }

        JPAQuery<HistoryListQueryResult> query = jpaQueryFactory
                .select(Projections.constructor(HistoryListQueryResult.class,
                        qDetectorHistoryData.id,
                        qDetectorHistoryData.detectorId,
                        qDetectorHistoryData.areaId,
                        qDetectorHistoryData.startTime,
                        qDetectorHistoryData.endTime,
                        qDetectorHistoryData.detectorStatus,
                        qDetectorHistoryData.detectorUnitState,
                        qDetectorHistoryData.alarmState,
                        qDetectorHistoryData.detectionModuleEnable,
                        qDetectorHistoryData.detectorModuleStatus,
                        qDetectorHistoryData.particleCount,
                        qDetectorHistoryData.particlePercent,
                        qDetectorHistoryData.smokeCount,
                        qDetectorHistoryData.smokePercent,
                        qDetector.detectorName.as("detectorName"),
                        qDetectorAreaInfo.areaName
                ))
                .from(qDetectorHistoryData)
                .where(builder)
                .leftJoin(qDetectorAreaInfo).on(qDetectorAreaInfo.id.eq(qDetectorHistoryData.areaId))
                .leftJoin(qDetector).on(qDetector.id.eq(qDetectorHistoryData.detectorId));

        List<HistoryListQueryResult> fetch = query
                .orderBy(qDetectorHistoryData.createDate.asc())
                .fetch();

        List<HistoryListResp> responses = new ArrayList<>();

        if (!fetch.isEmpty()){
            String firstRecordTime = fetch.get(0).getStartTime();
//            StringBuffer zeroTime = new StringBuffer(firstRecordTime).replace(11,20,"00:00:00");
            String format = "yyyy-MM-dd HH:mm:ss";

            for (int i = 0; i < fetch.size() - 1; i++) {
                String lastTime = fetch.get(i).getStartTime();
                String nextTime = fetch.get(i+1).getStartTime();
//                Long dataSize = dateDiff(zeroTime.toString(), lastTime, format, "s");
                long dataSize = currentTime(lastTime);
                Long diffNum = dateDiff(lastTime, nextTime, format, "s");

                for (int j = 0; j < diffNum - 1 ; j++) {
                    HistoryListResp response = new HistoryListResp();
                    BeanUtil.copyProperties(fetch.get(i), response, CopyOptions.create().setIgnoreNullValue(true));
                    response.setDetectorStatus(EnumHelper.getDetectorStatusDesc(fetch.get(i).getDetectorStatus()));
                    response.setAlarmState(EnumHelper.getAlarmStatusDesc(fetch.get(i).getAlarmState()));
                    response.setDetectionModuleEnable(EnumHelper.getDetectionModuleEnableDesc(fetch.get(i).getDetectionModuleEnable()));
                    response.setDetectorModuleStatus(EnumHelper.getDetectorModuleStatusDesc(fetch.get(i).getDetectorModuleStatus()));
                    long lTime = dataSize + j;
                    String sTime = convertSecondsToDateString(firstRecordTime,lTime);
//                    String sTime = secondToDate(lTime, format);
                    response.setStartTime(sTime);
                    responses.add(response);

//                    log.info("firstRecordTime ----> " + firstRecordTime
//                    + "lastTime----->" + lastTime + "nextTime ----> " + nextTime
//                    + "dataSize----->" + dataSize + "diffNum ---->" + diffNum
//                    + "lTime-->{}", lTime + "sTime--->" + sTime + "zeroTime" + zeroTime.toString());
                }
            }
        }

        return responses;
    }

    public static String convertSecondsToDateString(String dateTimeString, long seconds) {

        // 定义日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 解析字符串为LocalDateTime对象
        LocalDateTime dateTime = LocalDateTime.parse(dateTimeString, formatter);

        // 获取当前日期
//        LocalDateTime currentDate = LocalDateTime.now().toLocalDate().atStartOfDay();
        LocalDateTime currentDate = dateTime.toLocalDate().atStartOfDay();

        // 将秒数加到当前时间（分钟级别）上
        LocalDateTime targetTime = currentDate.plusSeconds(seconds);

        // 获取系统默认时区
        ZoneId zoneId = ZoneId.systemDefault();

        // 转换为带时区的时间
        ZonedDateTime zonedDateTime = targetTime.atZone(zoneId);

        // 输出零点时间
        System.out.println("今天的零点时间是: " + currentDate);

        // 格式化日期时间为字符串
        return zonedDateTime.format(formatter);

    }

    public long currentTime(String currentTimeStr){

        // 定义日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 解析字符串为 LocalDateTime 对象
        LocalDateTime currentTime = LocalDateTime.parse(currentTimeStr, formatter);

        // 获取当天的开始时间
        LocalDateTime startOfDay = currentTime.toLocalDate().atStartOfDay();

        // 计算两个时间点之间的秒数差
        long secondsOfDay = ChronoUnit.SECONDS.between(startOfDay, currentTime);

        return secondsOfDay;
    }


    /**
     * 秒转换为指定格式的日期
     * @param second
     * @param patten
     * @return
     */
    private String secondToDate(long second,String patten) {

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(second * 1000);//转换为毫秒
        Date date = calendar.getTime();
        SimpleDateFormat format = new SimpleDateFormat(patten);
        String dateString = format.format(date);
        return dateString;
    }

    public static Long dateDiff(String startTime, String endTime, String format, String str) {
        // 按照传入的格式生成一个simpledateformate对象
        SimpleDateFormat sd = new SimpleDateFormat(format);
        long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数
        long nh = 1000 * 60 * 60;// 一小时的毫秒数
        long nm = 1000 * 60;// 一分钟的毫秒数
        long ns = 1000;// 一秒钟的毫秒数
        long diff;
        long day = 0;
        long hour = 0;
        long min = 0;
        long sec = 0;
        String result = "0";
        // 获得两个时间的毫秒时间差异
        try {
            diff = sd.parse(endTime).getTime() - sd.parse(startTime).getTime();
            day = diff / nd;// 计算差多少天
            hour = diff % nd / nh + day * 24;// 计算差多少小时
            min = diff % nd % nh / nm + day * 24 * 60;// 计算差多少分钟
            sec = diff % nd % nh % nm / ns;// 计算差多少秒
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

//        System.out.println("时间相差：" + day + "天" + (hour - day * 24) + "小时"
//                + (min - day * 24 * 60) + "分钟" + sec + "秒。");

        if ("d".equalsIgnoreCase(str)){
            return day;
        } else if ("h".equalsIgnoreCase(str)) {
            return hour;
        } else if ("m".equalsIgnoreCase(str)){
            return min;
        } else if ("s".equalsIgnoreCase(str)){
            return sec;
        }
        else {
            return 0L;
        }

    }

    @Override
    public DetectorHistoryData findNewRecords(){
        return repository.findNewData();
    }

    /**
     * 分页显示探测器历史数据
     *
     * @param request
     * @param pageable
     * @return
     */
    @Override
    public Page<HistoryListResp> findAllRecord(HistoryListRequest request, Pageable pageable) {
        QDetectorHistoryData qDetectorHistoryData = QDetectorHistoryData.detectorHistoryData;
        QDetectorAreaInfo qDetectorAreaInfo = QDetectorAreaInfo.detectorAreaInfo;
        QDetector qDetector = QDetector.detector;

        BooleanBuilder builder = new BooleanBuilder();
        builder.and(qDetectorHistoryData.startTime.between(request.getStartTime(), request.getEndTime()));

        if (request.getDetectorId().size() > 0) {
            BooleanBuilder builder1 = new BooleanBuilder();
            for (String id : request.getDetectorId())
                builder1.or(qDetectorHistoryData.detectorId.eq(id));

            builder.and(builder1);
        }
        if (request.getAreaId().size() > 0) {
            BooleanBuilder builder1 = new BooleanBuilder();
            for (String id : request.getAreaId())
                builder1.or(qDetectorHistoryData.areaId.eq(id));

            builder.and(builder1);
        }

        JPAQuery<HistoryListQueryResult> query = jpaQueryFactory
                .select(Projections.constructor(HistoryListQueryResult.class,
                        qDetectorHistoryData.id,
                        qDetectorHistoryData.detectorId,
                        qDetectorHistoryData.areaId,
                        qDetectorHistoryData.startTime,
                        qDetectorHistoryData.endTime,
                        qDetectorHistoryData.detectorStatus,
                        qDetectorHistoryData.detectorUnitState,
                        qDetectorHistoryData.alarmState,
                        qDetectorHistoryData.detectionModuleEnable,
                        qDetectorHistoryData.detectorModuleStatus,
                        qDetectorHistoryData.particleCount,
                        qDetectorHistoryData.particlePercent,
                        qDetectorHistoryData.smokeCount,
                        qDetectorHistoryData.smokePercent,
                        qDetector.detectorName.as("detectorName"),
                        qDetectorAreaInfo.areaName
                ))
                .from(qDetectorHistoryData)
                .where(builder)
                .leftJoin(qDetectorAreaInfo).on(qDetectorAreaInfo.id.eq(qDetectorHistoryData.areaId))
                .leftJoin(qDetector).on(qDetector.id.eq(qDetectorHistoryData.detectorId));


//        query.leftJoin(qDetectorAreaInfo).on(qDetectorAreaInfo.id.eq(qDetectorHistoryData.areaId));
//        query.leftJoin(qDetector).on(qDetector.id.eq(qDetectorHistoryData.detectorId));

        List<HistoryListQueryResult> fetch = query
                .orderBy(qDetectorHistoryData.createDate.desc())
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();

        //long total = query.fetch().size();
//        long total = jpaQueryFactory().select(qDetectorHistoryData.count())
//                .from(qDetectorHistoryData)
//                .where(builder)
//                .fetchOne();
        long total = query.fetchCount();

        List<HistoryListResp> responses = new ArrayList<>();
        fetch.forEach(item -> {
            HistoryListResp response = new HistoryListResp();
            BeanUtil.copyProperties(item, response, CopyOptions.create().setIgnoreNullValue(true));
            response.setDetectorStatus(EnumHelper.getDetectorStatusDesc(item.getDetectorStatus()));
            response.setAlarmState(EnumHelper.getAlarmStatusDesc(item.getAlarmState()));
            response.setDetectionModuleEnable(EnumHelper.getDetectionModuleEnableDesc(item.getDetectionModuleEnable()));
            response.setDetectorModuleStatus(EnumHelper.getDetectorModuleStatusDesc(item.getDetectorModuleStatus()));
            responses.add(response);
        });
        return new PageImpl<>(responses, pageable, total);
    }
}
